package com.xhx.dao.mongodb;

import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.xhx.model.utils.PagingModel;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;

/**
 * 采用 MongoDB 数据库
 */
@Repository("primaryGisCoordinateMapper")
public class GisCoordinateMapper implements MongoRepository<GisCoordinate, String> {

    /**
     * 注入资源
     */
    @Resource
    @Qualifier("primaryMongoTemplate")
    private MongoTemplate mongoTemplate;

    /**
     * 添加
     *
     * @param gisCoordinate 实体
     * @return
     */
    public long addGisCoordinate(GisCoordinate gisCoordinate) {

        // ObjectId是一个12字节的 BSON 类型字符串，如："5ec32e5dbd545907c95acf0a"
        //        4字节：UNIX时间戳
        //        3字节：表示运行MongoDB的机器
        //        2字节：表示生成此_id的进程
        //        3字节：由一个随机数开始的计数器生成的值
        //ObjectId _id = new ObjectId();

        // 不为空才执行
        if (null != gisCoordinate) {
            // 生成主键（测试）
            //gisCoordinate.setGisType(_id.toString());

            try {

                // 插入一个集合
                //        List<GisCoordinate> gisCoordinateList = new ArrayList<>();
                //        gisCoordinateList.add(gisCoordinate);
                //        mongoTemplate.insert(gisCoordinateList, "GisCoordinate"); // insertAll

                // 插入一个实体
//                String collectionName = "GisCoordinate";
//                Index index = new Index();
//                index.on("gisUser", Sort.Direction.ASC);
//                mongoTemplate.indexOps(collectionName).ensureIndex(index);

                // 调用的是insert(T objectToSave)该方法,因为T是实体类,通过注解就知道查到哪个collection了,mango不需要先创建表,第一条插入的数据,发现没有对应的collection就会创建
                GisCoordinate result = mongoTemplate.insert(gisCoordinate, "GisCoordinate"); // 直接插入（单表）
                // GisCoordinate result = mongoTemplate.insert(gisCoordinate, "GisCoordinate_" + gisCoordinate.getGisUser()); // 直接插入（分表）
                // GisCoordinate result = mongoTemplate.save(gisCoordinate, "GisCoordinate"); // 遍历列表，然后插入

                // 返回主键值
                return result.getGisId();
            } catch (Exception e) {
                return 0L;
            }
        }

        return 0L;
    }

    /**
     * 删除
     *
     * @param id 主键
     */
    public long deleteGisCoordinateById(long id) {

        // 主键查询
        //Query query = new Query(Criteria.where("_id").is("5ec32e5dbd545907c95acf0a"));
        Query query = new Query(Criteria.where("_id").is(id));

        DeleteResult result = mongoTemplate.remove(query, GisCoordinate.class, "GisCoordinate");

        return result.getDeletedCount();
    }

    /**
     * 修改
     *
     * @param gisCoordinate
     */
    public long updateGisCoordinateById(GisCoordinate gisCoordinate) {

        // 主键查询
        Query query = new Query(Criteria.where("_id").is(gisCoordinate.getGisId())); //_id区分引号 "1"和1

        // 更新各个项
        Update update = new Update();
        update.set("GisLatitude", gisCoordinate.getGisLatitude());
        update.set("GisLongitude", gisCoordinate.getGisLongitude());

        // UpdateResult result = mongoTemplate.updateMulti(query, update, "GisCoordinate"); //查询到的全部更新
        // UpdateResult result = mongoTemplate.updateFirst(query, update, "GisCoordinate"); //查询更新第一条
        // UpdateResult result = mongoTemplate.upsert(query, update, "GisCoordinate"); //有则更新，没有则新增
        // return result.getN(); //返回执行的条数

        // 更新查询返回结果集的第一条
        UpdateResult result = mongoTemplate.updateFirst(query, update, GisCoordinate.class, "GisCoordinate");
        // 更新查询返回结果集的所有
        // mongoTemplate.updateMulti(query, update, GisCoordinate.class, "GisCoordinate");
        if (result != null)
            //return result.getUpsertedId(); //
            return result.getModifiedCount(); // 修改计数
            //return result.getMatchedCount(); // 匹配计数
        else
            return 0L;
    }

    /**
     * 查找
     *
     * @param id 主键
     * @return
     */
    public GisCoordinate getGisCoordinateById(long id) {
        //        Query query = new Query();
        //        query.addCriteria(Criteria.where("username").is(username));
        //        return mongoTemplate.findOne(query, User.class);

        // 主键查询（精确匹配）
        Query query = new Query(Criteria.where("_id").is(id));

        // 模糊匹配
        //Pattern pattern = Pattern.compile("^.*8$", Pattern.CASE_INSENSITIVE);
        //Query query2 = new Query(Criteria.where("_id").regex(pattern));

        return mongoTemplate.findOne(query, GisCoordinate.class, "GisCoordinate");
    }

    /**
     * 列表，并分页
     *
     * @param pagingModel:分页模型
     * @param filterModel:过滤模型
     * @return 实体集
     */
    public List<GisCoordinate> getAllGisCoordinate(@Param("pagingModel") PagingModel pagingModel, @Param("filterModel") GisCoordinate filterModel) {

        Query query = new Query();
        Criteria criteria = new Criteria();

        // 添加条件 filterModel
        criteria.andOperator(Criteria.where("gisUser").is(filterModel.getGisUser()));

        // 下面条件相当于select * from order where orderStatus in(16,32) and payStatus=4 and finishTime<=2019-07-05 00:00:00 and (customerId=139 or customerId=1360)
//        criteria.and("orderStatus").in(16, 32).andOperator(Criteria.where("payStatus").is(4))
//                .and("finishTime").lte("2019-07-05 00:00:00")
//                .orOperator(Criteria.where("customerId").is("139"), Criteria.where("customerId").is("1360"));

        // 添加检索条件
        query.addCriteria(criteria);
        //System.out.println(JSON.toJSONString(criteria));

        // 获得符合条件的记录总数
        long count = mongoTemplate.count(query, GisCoordinate.class, "GisCoordinate"); //计算总数,用于算法分页数
        //System.out.println(count);

        // 回传
        pagingModel.count = (int) count;

        int pageNum = pagingModel.page;
        int pageSize = pagingModel.size;
        int pageTotal = (int) (count % pageSize == 0 ? count / pageSize : count / pageSize + 1); //总页数
        System.out.println(pageTotal);
        int offset = (pageNum - 1) * pageSize;

        //query.with(Sort.by(Sort.Order.asc("sendTime"), Sort.Order.desc("_id"))); // 排序逻辑
        query.with(Sort.by(Sort.Order.desc("_id"))); // 排序逻辑
        query.skip(offset).limit(pageSize); // 分页逻辑

        // 排序
        //Sort sort = new Sort(Sort.Direction.ASC, "DEVID").and(new Sort(Sort.Direction.ASC, "TIME")); //多条件
        //Sort sort = new Sort(); //多条件
        //query.with(new Sort(Sort.Direction.DESC, "_id"));

        // 聚合操作
        //Aggregation aggregation = Aggregation.newAggregation(
//
        //java的bigDeciaml类型在mongodb中会变成字符串,所以对bigDeciaml进行sum操作,永远都是返回0
        //match是条件:match在group后面就相当于where 语句,在后面相当于having语句,sort要在group后面才有意义

//                // 第一步：挑选所需的字段，类似select *，*所代表的字段内容
//                Aggregation.project("begin", "end", "userId", "distance"),
//                // 第二步：sql where 语句筛选符合条件的记录
////            Aggregation.match(Criteria.where("userId").is(map.get("userId"))),
//                // 第三步：分组条件，设置分组字段
//                Aggregation.group("userId").sum("distance").as("distance"), // count
//                // 第四部：排序（根据某字段排序 倒序）
//                Aggregation.sort(Sort.Direction.DESC,"distance"),
//                // 第五步：数量(分页)
//                //Aggregation.limit(Integer.parseInt(map.get("pagesCount"))),
//                // 第六步：重新挑选字段
//                Aggregation.project("userId","distance")
        //);

        //AggregationResults<JSONObject> results = mongoTemplate.aggregate(aggregation, "GisCoordinate", JSONObject.class);
        //List<JSONObject> mappedResults = results.getMappedResults();

        // 查找符合条件的当前页记录集合
        return mongoTemplate.find(query, GisCoordinate.class, "GisCoordinate"); // findDistinct 去重
    }

    public void aggress() {
        //java的bigDeciaml类型在mongodb中会变成字符串,所以对bigDeciaml进行sum操作,永远都是返回0
        //match是条件:match在group后面就相当于where 语句,在后面相当于having语句,sort要在group后面才有意义
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.group("orderStatus").count().as("total")
                        .sum("orderPayAmount").as("payAmount")
                        .first("orderStatus").as("orderStatus")

        ).withOptions(Aggregation.newAggregationOptions().allowDiskUse(true).build());

        //如果不加first的时候,取不到orderStatus的值,所以加了后,分组的值才会有数据
        //Aggregation.newAggregationOptions().allowDiskUse(true)是用来解除mongodb 查询数据默认占用最大内存的(默认100M).不然会抛出异常:
        AggregationResults<GisCoordinate> order = mongoTemplate.aggregate(aggregation, "order", GisCoordinate.class);
        List<GisCoordinate> mappedResults = order.getMappedResults();

        System.out.println(mappedResults);
        System.out.println(order);
    }

    /**
     * 列表，记录总数
     *
     * @param filterModel:过滤模型
     * @return 记录总数
     */
    public long getAllGisCoordinateCount(@Param("filterModel") GisCoordinate filterModel) {

        // 多条件查询
        Criteria c = new Criteria();
        //c.and(key).is(value);
        //c.and("GisId").is(filterModel.getGisId());

        Query query = Query.query(c);

        // 获得符合条件的记录总数
        return mongoTemplate.count(query, GisCoordinate.class, "GisCoordinate");
    }

    @Override
    public <S extends GisCoordinate> S save(S s) {
        return null;
    }

    @Override
    public <S extends GisCoordinate> List<S> saveAll(Iterable<S> iterable) {
        return null;
    }

    @Override
    public Optional<GisCoordinate> findById(String s) {
        return Optional.empty();
    }

    @Override
    public boolean existsById(String s) {
        return false;
    }

    @Override
    public List<GisCoordinate> findAll() {
        return null;
    }

    @Override
    public Iterable<GisCoordinate> findAllById(Iterable<String> iterable) {
        return null;
    }

    @Override
    public long count() {
        return 0;
    }

    @Override
    public void deleteById(String s) {

    }

    @Override
    public void delete(GisCoordinate gisCoordinate) {

    }

    @Override
    public void deleteAll(Iterable<? extends GisCoordinate> iterable) {

    }

    @Override
    public void deleteAll() {

    }

    @Override
    public List<GisCoordinate> findAll(Sort sort) {
        return null;
    }

    @Override
    public Page<GisCoordinate> findAll(Pageable pageable) {
        return null;
    }

    @Override
    public <S extends GisCoordinate> S insert(S s) {
        return null;
    }

    @Override
    public <S extends GisCoordinate> List<S> insert(Iterable<S> iterable) {
        return null;
    }

    @Override
    public <S extends GisCoordinate> Optional<S> findOne(Example<S> example) {
        return Optional.empty();
    }

    @Override
    public <S extends GisCoordinate> List<S> findAll(Example<S> example) {
        return null;
    }

    @Override
    public <S extends GisCoordinate> List<S> findAll(Example<S> example, Sort sort) {
        return null;
    }

    @Override
    public <S extends GisCoordinate> Page<S> findAll(Example<S> example, Pageable pageable) {
        return null;
    }

    @Override
    public <S extends GisCoordinate> long count(Example<S> example) {
        return 0;
    }

    @Override
    public <S extends GisCoordinate> boolean exists(Example<S> example) {
        return false;
    }

}
